#ifndef GAME_H
#define GAME_H



#include "includes.h"
#include "init.h"
#include "players.h"



class object;
class unit;

class player;

class game_state;



/** @brief Main class, that takes care of the whole game logics
*
*   \image html game.jpeg
*/
class game: public QObject
{

	Q_OBJECT

public:

	/**	@brief	Function for obaining the singleton
	*	@return	pointer to the singleton
	*/
	static game* get_instance();

	//! @brief Deletes recorded commands, score and stored state and recreates all structures and flags
	void rebuild();


	//! @brief Forces AI player to send next command in "ai_delay" time
	void get_next_ai_command();
	//! @brief Forces AI player to send next command now
	void get_next_ai_command_now();
	//! @brief Clears AI player's command queue and adds NXT command there
	void stop_ai();

	/** @brief Sets beginning player in buy mode, sets START_TIME, creates beginning game_state and saves beginning score
	*	@param start_player starting player;
	*	@param replay if game is replay, or real game
	*/
	void start_buy( unsigned int start_player = 0, bool replay = false );
	//! @brief Sets beginning player, creates all structures for game info, sets START_TIME, creates beginning game_state and saves beginning score
	void start_game();
	//! @brief Gets next player in buy mode, sets START_TIME, sets game_state not up to date, saves score
	void next_turn_buy();
	//! @brief Gets next player, sets START_TIME, sets game_state not up to date, saves score
	void next_turn();
	//! @brief Gets next player and sets START_TIME ( for buying new units )
	void end_buy();
	/** @brief	Tests if there are at least two players playing
	*	@return	pointer to the winner and saves score or 0 if game continues
	*/
	player* test_game_end();

	/** @brief	Gets current player
	*	@return	pointer to the current player
	*/
	player* get_current_player();
	/** @brief Sets player with specified place in palyers array
	*	@param n place of the player
	*/
	void set_current_player( unsigned int n );
	
	/** @brief	Tests if player can play (local && on turn)
	*	@param	p palyer to test
	*	@return true if can, else false
	*/
	bool can_play( const player* p );

	/** @brief	Checks if the game is paused
	*	@return	true, if it is, else false
	*/
	bool is_paused();
	/** @brief Pauses/unpauses game
	*	@param paused true == pause, false == unpause
	*/
	void set_paused( bool paused );

	/** @brief	Checks if game is network or local
	*	@return	true if game is played over network, else false
	*/
	bool is_network_game();
	/** @brief Sets game type information (network/local)
	*	@param net_game true if game is network, false if local
	*/
	void set_network_game( bool net_game );


	/** @brief	Gets current game state
	*	@return	current game state
	*/
	game_state* get_current_state();

	//! @brief Stores all starting objects to string in case of exporting at the end of the game
	void save_starting_objects();

	/**	@brief Saves all players commands to file
	*	@param file filename where to save commands
	*/
	void export_players_commands( const char* file );

	/**	@brief Saves all starting objects to file
	*	@param file filename where to save objects
	*/
	void export_starting_objects( const char* file );

	
	/** @brief Saves score to history of scores
	*	@param state game state from which to save score, constraint: state != 0
	*/
	void set_score_to_history( game_state* state );
	/** @brief	Gets game score history
	*	@return	matrix of scores
	*/
	vector< vector< double > >* get_score_history();

	/** @brief	Checks if game is replay, or real
	*	@return	true if replay, else false
	*/
	bool is_replay()
	{
		return replayed_game;
	};

	/** @brief Set application mode
	*	@param testing if application will show commands in gui, or not
	*/
	void set_testing_mode( bool testing )
	{
		testing_mode = testing;
	};
	/** @brief	Check application mode
	*	@return	true, if application is in testing mode, or not
	*/
	bool is_in_testing_mode()
	{
		return testing_mode;
	};


	/** @brief	Creates command from given parameters
	*	@param	c commant type
	*	@param	u unit number
	*	@param	x x coordinate
	*	@param	y y coordinate
	*	@return	generated command
	*/
	static string create_command( const string& c, unsigned int u, unsigned int x, unsigned int y );
	/** @brief	Creates command from given parameters
	*	@param	c commant type
	*	@param	u unit number
	*	@return	generated command
	*/
	static string create_command( const string& c, unsigned int u );

	//! starting objects (objects before first turn, but after buy)
	string starting_objects;

	int x;


private:

	game( int _x );
	game( const game& );
	game& operator=( const game& x );
	//! @brief Deletes recorded commands and stored state
	~game();


	//! @brief Checks, if all loaded units from file can really be loaded bue to game constraints and deletes thou, that can't
	void check_loaded_units();


	//!pointer co the current_player, initially first player from the players array
	player* current_player;

	//! status of ai, initially paused
	bool ai_paused;

	//! if the application is in testing mode a will not show gui, or not
	bool testing_mode;

	//! flag if game is network or local
	bool network_game;

	//! if game is currently in buy mode
	bool buy_mode;

	//! current game state
	game_state* current_state;
	//! if current game state is up to date
	bool up_to_date;

	//! matrix of game scores
	vector< vector< double > >* score_history;

	//! vector of all players commands
	vector< list< string >* >* players_commands;

	//! if game is replay, or real game
	bool replayed_game;

	//! how many players finished buy
	unsigned int finished_buy;

	//! if game ended, or not
	bool game_ended;


public slots:

	//! @brief Slot for receiving commands from players
	void command_received( player* pl, const string& command );

};



#endif